/**
 * Copyright (c) <2010>, <SUNNY GUPTA>
 * All rights reserved.

 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the <ORGANIZATION> nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <SUNNY GUPTA> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.gwtp.investmentadvisor.server.authentication.actionhandler;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.inject.Inject;
import com.gwtp.investmentadvisor.server.authentication.AuthenticationManager;
import com.gwtp.investmentadvisor.server.authentication.exception.SessionIDGenerationFailedException;
import com.gwtp.investmentadvisor.shared.action.LoginAttempt;
import com.gwtp.investmentadvisor.shared.action.LoginAttemptResult;
import com.gwtp.investmentadvisor.shared.entities.LoginAuthenticationInfo;
import com.gwtp.investmentadvisor.shared.entities.LoginInfo;
import com.gwtp.investmentadvisor.shared.entities.UserRole;
import com.gwtplatform.dispatch.server.ExecutionContext;
import com.gwtplatform.dispatch.server.actionhandler.ActionHandler;
import com.gwtplatform.dispatch.shared.ActionException;

/**
 * 
 * @author Sunny Gupta
 *
 */
public class LoginAttemptHandler implements
    ActionHandler<LoginAttempt, LoginAttemptResult> {
  
  private final AuthenticationManager authenticationManager;

  private static final String FAILURE_MESSAGE = "Login authentication failed";
  
  private static final Logger logger = Logger.getLogger(LoginAttemptHandler.class.getName());

  @Inject
  public LoginAttemptHandler(final AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
  }

  private LoginAuthenticationInfo checkUserCredentials(LoginInfo loginInfo) throws SessionIDGenerationFailedException {
    String username = loginInfo.getUserName();
    // Authenticate user
    boolean isAuthenticated = authenticationManager.authenticateUser(username,loginInfo.getPassWord());
    
    String sessionID = null;
    List<UserRole> userRoles = null;

    if (isAuthenticated) {
      // Obtain sessionID
      sessionID = authenticationManager.getSessionID(username);
      userRoles = authenticationManager.getUserRoles(username);
    }
    
    // Form LoginAuthenticationInfo & return
    LoginAuthenticationInfo sessionInfo = new LoginAuthenticationInfo();
    sessionInfo.setSessionID(sessionID);
    sessionInfo.setAuthenticated(isAuthenticated);
    sessionInfo.setUsername(username);
    sessionInfo.setUserRoles(userRoles);
    
    // Return
    return sessionInfo;
  }

  @Override
  public Class<LoginAttempt> getActionType() {
    return LoginAttempt.class;
  }

  @Override
  public LoginAttemptResult execute(LoginAttempt action,
      ExecutionContext context) throws ActionException {
    try {
      // Authenticate user
      LoginAuthenticationInfo authenticationInfo = checkUserCredentials(action.getLoginInfo());
      
      // Form result
      LoginAttemptResult result = new LoginAttemptResult(action.getLoginInfo(), authenticationInfo);
      
      // return
      return result;
    } catch (Exception e) {
      // Log error
      logger.log(Level.SEVERE, FAILURE_MESSAGE, e);
      
      // Throw exception
      throw new ActionException(e);
    }
  }

  @Override
  public void undo(LoginAttempt action, LoginAttemptResult result,
      ExecutionContext context) throws ActionException {
    // TODO: Rethink as we may want to undo sessionID generation. Nothing to do here as it's a read only action
  }

}
